package com.witframework.util;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.springframework.util.Assert;

import com.witframework.WitException;

public class CryptoUtility {
	private static Cipher s_cipher = null;
	private static SecretKey s_key = null;

	public CryptoUtility() {
	}

	public static void main(String argv[]) throws Exception {
		System.out.println("Enter encryption password:  ");
		System.out.flush();
		String clave = argv[0];
		System.out.println("************* " + clave);
		String strEnc = new String(CryptoUtility.encrypt(clave));
		System.out.println("ENCRYPTED TEXT: " + strEnc);
		System.out.println("DECRYPTED TEXT: " + CryptoUtility.decrypt(strEnc));
		encryptFile("12345678","E:\\file-backup\\myproject\\src\\config\\application.properties",null);
	}

	public static byte[] stringToByteArray(String input) {
		Assert.hasLength(input, "Input required");
		try {
			return input.getBytes();
		} catch (Exception fallbackToDefault) {
			return input.getBytes();
		}
	}

	private static void initCipher() {
		try {
			// not change s_key value!!!
			s_key = new SecretKeySpec(new byte[] { 100, 125, 28, -122, -26, 94, -3, -72 }, "DES");
			s_cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	public static byte[] encrypt(String key, String value) throws WitException {
		return encrypt(key, stringToByteArray(value));
	}

	public static byte[] encrypt(String value) throws WitException {
		return encrypt(stringToByteArray(value), null);
	}

	public static byte[] encrypt(byte[] value) throws WitException {
		return encrypt(value, null);
	}

	public static byte[] encrypt(String key, byte[] value) throws WitException {
		if (key == null)
			return encrypt(value, s_key);
		SecretKey _s_key = new SecretKeySpec(new byte[] { 100, 125, 28, -122, -26, 94, -3, -72 }, "DES");
		return encrypt(value, _s_key);
	}

	private static byte[] encrypt(byte[] value, SecretKey _s_key) throws WitException {
		if (s_cipher == null)
			initCipher();
		if (_s_key == null)
			_s_key = s_key;
		byte encString[];
		byte clearText[];
		clearText = value;
		if (clearText.length == 0)
			return value;		
		if (s_cipher == null)
			throw new WitException("CryptoUtility.encrypt() - Can't load cipher");
		String result = "";
		try {
			s_cipher.init(Cipher.ENCRYPT_MODE, _s_key);
			encString = s_cipher.doFinal(clearText);
			return org.apache.commons.codec.binary.Base64.encodeBase64(encString);
		} catch (Exception ex) {
			throw new WitException("CryptoUtility.encrypt() - Can't init cipher", ex);
		}
	}

	public static byte[] decrypt(byte[] value) throws WitException {
		return decrypt(value, null);

	}

	public static byte[] decrypt(String key, byte[] value) throws WitException {
		SecretKey _s_key = new SecretKeySpec(stringToByteArray(key), "DES");
		return decrypt(value, _s_key);
	}

	private static byte[] decrypt(byte[] value, SecretKey _s_key) throws WitException {
		if (s_cipher == null)
			initCipher();
		if (_s_key == null)
			_s_key = s_key;
		if (value == null)
			return null;
		if (value.length == 0)
			return value;
		
		if (s_cipher == null || value == null || value.length <= 0)
			throw new WitException("CryptoUtility.decrypt() - Can't load cipher");
		byte out[];
		byte decode[];
		try {
			decode = org.apache.commons.codec.binary.Base64.decodeBase64(value);
			s_cipher.init(Cipher.DECRYPT_MODE, s_key, s_cipher.getParameters());
			out = s_cipher.doFinal(decode);
		} catch (Exception ex) {
			ex.printStackTrace();
			throw new WitException("CryptoUtility.decrypt() - Can't init cipher");
		}
		return out;
	}

	public static String decrypt(String value) throws WitException {
		try {
			return new String(decrypt(value.getBytes()), "utf-8");
		} catch (UnsupportedEncodingException e) {
			throw new WitException("CryptoUtility.decrypt() - UnsupportedEncodingException");
		}
	}

	public static InputStream encrypt(String key, InputStream in) throws IOException {
		byte[] contents = new byte[in.available()];
		in.read(contents);
		InputStream enIn = new java.io.ByteArrayInputStream(encrypt(key, contents));
		return enIn;
	}
	public static void encryptFile(String key, String inPath,String outPath) throws IOException {
		FileInputStream in=null;
		FileOutputStream out=null;
		FileOutputStream keyFile=null;
		if(outPath==null) outPath=inPath+".encrypt";
		try{
			in=new FileInputStream(inPath);
			byte[] contents = new byte[in.available()];
			in.read(contents);		
			out=new FileOutputStream(outPath);
			out.write(encrypt(key, contents));	
			keyFile=new FileOutputStream(inPath+".key");
			keyFile.write(encrypt(key));
		}finally{
			if(out!=null)
				out.close();
			if(out!=null)
				in.close();
			if(keyFile!=null)
				keyFile.close();
		}
	}
	public static InputStream decrypt(String key, InputStream in) throws IOException {
		byte[] contents = new byte[in.available()];
		in.read(contents);
		InputStream enIn = new java.io.ByteArrayInputStream(decrypt(key, contents));
		return enIn;
	}
	public static InputStream decrypt(InputStream keyFile, InputStream in) throws IOException {
		byte[] keys = new byte[keyFile.available()];
		keyFile.read(keys);
		byte[] contents = new byte[in.available()];
		in.read(contents);
		InputStream enIn = new java.io.ByteArrayInputStream(decrypt(new String(decrypt(keys)), contents));
		return enIn;
	}

	
}
